package com.see.client;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.JLabel;

import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Label;

import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JComboBox;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.FlowLayout;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.swing.JTable;

import com.see.client.exception.BadOrderException;
import com.see.domain.Operation;
import com.see.domain.Order;
import com.see.domain.Price;
import com.see.domain.Protocol;
import com.see.exception.MessegeFeedException;
import com.see.exception.UserExistException;

import javax.swing.JScrollBar;

public class ClientMainGUI extends JFrame {
	
	TradingClientImpl tradeingclient;
	
	private JPanel contentPane;
	
	private boolean productEntered = false;
	private boolean amountEntered = false;
	private boolean priseEntered = false;
	private boolean connected = false;
	private String userName;
	
	//Label
	private JLabel Label_Product;
	private JLabel Label_Amount;
	private JLabel lblPrice;
	private JLabel Label_Operation;
	private JLabel Label_Status;
	private JLabel Label_Type;
	
	//Text Fields
	private JTextField Field_Product;
	private JTextField Field_Amount;
	private JTextField Field_Prise;
	
	//ComboBox
	private JComboBox comboBox_Operation;
	private JComboBox comboBox_Type;
	
	private JTable table;
	private TableModel orderTableModel;
	//
	private JButton Button_Add;
	private JButton Button_Connect; 
	private JButton Button_Disconnect;
	

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ClientMainGUI frame = new ClientMainGUI();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public ClientMainGUI() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("Test");
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		
		JPanel panel = new JPanel();
		contentPane.add(panel, BorderLayout.NORTH);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[] {102, 63, 64, 0, 85};
		gbl_panel.rowHeights = new int[] {0, 0, 0, 0};
		gbl_panel.columnWeights = new double[]{1.0, 1.0, 1.0, 1.0, 1.0};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0};
		panel.setLayout(gbl_panel);
		
		Button_Connect = new JButton("Connect");
		GridBagConstraints gbc_Button_Connect = new GridBagConstraints();
		gbc_Button_Connect.insets = new Insets(0, 0, 5, 5);
		gbc_Button_Connect.gridx = 0;
		gbc_Button_Connect.gridy = 0;
		panel.add(Button_Connect, gbc_Button_Connect);
		
		Button_Disconnect = new JButton("Disconnect");
		GridBagConstraints gbc_Button_Disconnect = new GridBagConstraints();
		gbc_Button_Disconnect.insets = new Insets(0, 0, 5, 5);
		gbc_Button_Disconnect.gridx = 1;
		gbc_Button_Disconnect.gridy = 0;
		panel.add(Button_Disconnect, gbc_Button_Disconnect);
		
		Label_Status = new JLabel("");
		GridBagConstraints gbc_Label_Status = new GridBagConstraints();
		gbc_Label_Status.insets = new Insets(0, 0, 5, 5);
		gbc_Label_Status.gridx = 3;
		gbc_Label_Status.gridy = 0;
		panel.add(Label_Status, gbc_Label_Status);
		
		Label_Product = new JLabel("Product");
		GridBagConstraints gbc_Label_Product = new GridBagConstraints();
		gbc_Label_Product.anchor = GridBagConstraints.NORTHWEST;
		gbc_Label_Product.insets = new Insets(0, 0, 5, 5);
		gbc_Label_Product.gridx = 0;
		gbc_Label_Product.gridy = 1;
		panel.add(Label_Product, gbc_Label_Product);
		
		Label_Amount = new JLabel("Amount");
		GridBagConstraints gbc_Label_Amount = new GridBagConstraints();
		gbc_Label_Amount.anchor = GridBagConstraints.NORTHWEST;
		gbc_Label_Amount.insets = new Insets(0, 0, 5, 5);
		gbc_Label_Amount.gridx = 1;
		gbc_Label_Amount.gridy = 1;
		panel.add(Label_Amount, gbc_Label_Amount);
		
		Label_Operation = new JLabel("Operation");
		GridBagConstraints gbc_Label_Operation = new GridBagConstraints();
		gbc_Label_Operation.insets = new Insets(0, 0, 5, 5);
		gbc_Label_Operation.gridx = 2;
		gbc_Label_Operation.gridy = 1;
		panel.add(Label_Operation, gbc_Label_Operation);
		
		Label_Type = new JLabel("Type");
		GridBagConstraints gbc_Label_Type = new GridBagConstraints();
		gbc_Label_Type.insets = new Insets(0, 0, 5, 5);
		gbc_Label_Type.anchor = GridBagConstraints.NORTHEAST;
		gbc_Label_Type.gridx = 3;
		gbc_Label_Type.gridy = 1;
		panel.add(Label_Type, gbc_Label_Type);
		
		lblPrice = new JLabel("Price");
		GridBagConstraints gbc_lblPrice = new GridBagConstraints();
		gbc_lblPrice.insets = new Insets(0, 0, 5, 0);
		gbc_lblPrice.gridx = 4;
		gbc_lblPrice.gridy = 1;
		panel.add(lblPrice, gbc_lblPrice);
		
		Field_Product = new JTextField();
		GridBagConstraints gbc_Field_Product = new GridBagConstraints();
		gbc_Field_Product.insets = new Insets(0, 0, 5, 5);
		gbc_Field_Product.fill = GridBagConstraints.HORIZONTAL;
		gbc_Field_Product.gridx = 0;
		gbc_Field_Product.gridy = 2;
		panel.add(Field_Product, gbc_Field_Product);
		Field_Product.setColumns(10);
		
		Field_Amount = new JTextField();
		GridBagConstraints gbc_Field_Amount = new GridBagConstraints();
		gbc_Field_Amount.insets = new Insets(0, 0, 5, 5);
		gbc_Field_Amount.fill = GridBagConstraints.HORIZONTAL;
		gbc_Field_Amount.gridx = 1;
		gbc_Field_Amount.gridy = 2;
		panel.add(Field_Amount, gbc_Field_Amount);
		Field_Amount.setColumns(10);
		
		comboBox_Operation = new JComboBox(Operation.values());
		GridBagConstraints gbc_comboBox_Operation = new GridBagConstraints();
		gbc_comboBox_Operation.insets = new Insets(0, 0, 5, 5);
		gbc_comboBox_Operation.fill = GridBagConstraints.HORIZONTAL;
		gbc_comboBox_Operation.gridx = 2;
		gbc_comboBox_Operation.gridy = 2;
		panel.add(comboBox_Operation, gbc_comboBox_Operation);
		
		comboBox_Type = new JComboBox(OrderType.values());
		GridBagConstraints gbc_comboBox_Type = new GridBagConstraints();
		gbc_comboBox_Type.insets = new Insets(0, 0, 5, 5);
		gbc_comboBox_Type.fill = GridBagConstraints.HORIZONTAL;
		gbc_comboBox_Type.gridx = 3;
		gbc_comboBox_Type.gridy = 2;
		panel.add(comboBox_Type, gbc_comboBox_Type);
		
		Field_Prise = new JTextField();
		GridBagConstraints gbc_Field_Prise = new GridBagConstraints();
		gbc_Field_Prise.insets = new Insets(0, 0, 5, 0);
		gbc_Field_Prise.fill = GridBagConstraints.HORIZONTAL;
		gbc_Field_Prise.gridx = 4;
		gbc_Field_Prise.gridy = 2;
		panel.add(Field_Prise, gbc_Field_Prise);
		Field_Prise.setColumns(10);
		
		Button_Add = new JButton("AddOrder");
		GridBagConstraints gbc_Button_Add = new GridBagConstraints();
		gbc_Button_Add.gridx = 4;
		gbc_Button_Add.gridy = 3;
		Button_Add.setEnabled(false);
		panel.add(Button_Add, gbc_Button_Add);
		
		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.CENTER);
		panel_1.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        GridBagLayout gbl_panel_1 = new GridBagLayout();
        gbl_panel_1.rowWeights = new double[]{1.0};
        gbl_panel_1.columnWeights = new double[]{1.0};
        panel_1.setLayout(gbl_panel_1);
        
        orderTableModel = new OrderTableModel();
		table = new JTable(orderTableModel);
		JScrollPane scroll = new JScrollPane(table);
        GridBagConstraints gbc_table = new GridBagConstraints();
        gbc_table.insets = new Insets(0, 0, 5, 0);
        gbc_table.fill = GridBagConstraints.BOTH;
        gbc_table.gridx = 0;
        gbc_table.gridy = 0;
        panel_1.add(scroll, gbc_table);
        
        
        Button_Connect.addActionListener(new LoginActivator());
        Button_Disconnect.addActionListener(new DisconnectActivator());
        Button_Add.addActionListener(new SubmitListener());
        
    	SubmitActivator activator = new SubmitActivator();
		Field_Product.addKeyListener(activator);
		Field_Amount.addKeyListener(activator);
		Field_Prise.addKeyListener(activator);
		
		comboBox_Type.addItemListener(new PriceListener());
		
		comboBox_Type.setSelectedItem(OrderType.MARKET);
		
        activateSubmit();
        updateLabel_Status(false);
	}
	
	private void activateSubmit() {
	        OrderType type = (OrderType) comboBox_Type.getSelectedItem();
	        boolean activate = productEntered && amountEntered;

	        if(type == OrderType.MARKET)
	            Button_Add.setEnabled(activate);
	        else if(type == OrderType.LIMIT)
	        	Button_Add.setEnabled(activate && priseEntered);
	      
	}
	
	enum OrderType {
		MARKET("MARKET"), LIMIT("LIMIT");

		private final String type;

		private OrderType(final String type) {
			this.type = type;
		}

		public String getBookSide() {
			return type;
		}
	}
	
	
	private class DisconnectActivator implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent event) {
			if (!connected) {
				JOptionPane.showMessageDialog(null, "You are not connected",
						Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
				return;
			}
			
			disconnected();		
			
		}
	
	}
	
	private class SubmitListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent event) {

			if (!connected) {
				JOptionPane.showMessageDialog(null, "You are not connected",
						Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
				return;
			}

			String product = Field_Product.getText();
			int amount = 0;
			try {
				amount = Integer.parseInt(Field_Amount.getText());
			} catch (NumberFormatException e) {
				JOptionPane.showMessageDialog(null, e.getMessage(),
						Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
				return;
			}
			Operation oper = (Operation) comboBox_Operation.getSelectedItem();

			OrderType ot = (OrderType) comboBox_Type.getSelectedItem();
			Price price = null;
			if (ot == OrderType.MARKET) {
				price = new Price();
			} else {
				BigDecimal l_value; 
				try {
					l_value = new BigDecimal(Field_Prise.getText());;
				} catch (NumberFormatException e) {
					JOptionPane.showMessageDialog(null, e.getMessage(),
							Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
					return;
				}
				
				price = new Price(l_value);
			}

			Order order = new Order(userName, product, price, amount, oper);

			try {
				int orderid = tradeingclient.sendOrder(order);
				order.setId(orderid);
			} catch (BadOrderException | MessegeFeedException e) {
				JOptionPane.showMessageDialog(null, e.getMessage(),
						Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
				return;
			}

			((OrderTableModel) orderTableModel).addOrder(order);

		}
	}

	private class SubmitActivator implements KeyListener, ItemListener {
		public void keyReleased(KeyEvent e) {
			Object obj = e.getSource();
			if (obj == Field_Product) {
				productEntered = testField(obj);
			} else if (obj == Field_Amount) {
				amountEntered = testField(obj);
			} else if (obj == Field_Prise) {
				priseEntered = testField(obj);
			}
			activateSubmit();
		}

		public void itemStateChanged(ItemEvent e) {
			// sessionEntered = sessionComboBox.getSelectedItem() != null;
			activateSubmit();
		}

		private boolean testField(Object o) {
			String value = ((JTextField) o).getText();
			value.trim();
			return value.length() > 0;
		}

		public void keyTyped(KeyEvent e) {
		}

		public void keyPressed(KeyEvent e) {
		}
	}
	
	private class PriceListener implements ItemListener {
        public void itemStateChanged(ItemEvent e) {
            OrderType item = (OrderType) comboBox_Type.getSelectedItem();
            if (item == OrderType.MARKET) {
                enableLimitPrice(false);
            } else if(item == OrderType.LIMIT) {
                enableLimitPrice(true);
            } else {
                enableLimitPrice(true);
            }
            activateSubmit();
        }

        private void enableLimitPrice(boolean enabled) {
            Color labelColor = enabled ? Color.black : Color.gray;
            Color bgColor = enabled ? Color.white : Color.gray;
            Field_Prise.setEnabled(enabled);
            Field_Prise.setBackground(bgColor);
            lblPrice.setForeground(labelColor);
        }

    }
	
	private class LoginActivator implements ActionListener {
		Login lofin_frame; 
		@Override
		public void actionPerformed(ActionEvent event) {
			if (connected) {
				JOptionPane.showMessageDialog(null, "You are alredy connected",
						Protocol.ERROR_FIELD, JOptionPane.ERROR_MESSAGE);
				return;
			}
			try {
				lofin_frame = new Login();
				lofin_frame.setSize(300, 100);
				lofin_frame.setVisible(true);
			} catch (Exception except) {
				JOptionPane.showMessageDialog(null, except.getMessage());
			}
		}

		class Login extends JFrame implements ActionListener {
			JButton SUBMIT;
			JPanel panel;
			JLabel label_UserName;
			JLabel label_Port;
			JLabel label_ServerAdres;
			final JTextField Field_UserName;
			final JTextField Field_Port;
			final JTextField Field_ServerAdres;

			Login() {
				label_UserName = new JLabel();
				label_UserName.setText("Username:");
				Field_UserName = new JTextField(15);
				Field_UserName.setText("user");

				label_Port = new JLabel();
				label_Port.setText("Port:");
				Field_Port = new JTextField(15);
				Field_Port.setText("3000");

				label_ServerAdres = new JLabel();
				label_ServerAdres.setText("ServerAdress:");
				Field_ServerAdres = new JTextField(30);
				Field_ServerAdres.setText("localhost");

				SUBMIT = new JButton("SUBMIT");

				panel = new JPanel(new GridLayout(4, 1));
				panel.add(label_UserName);
				panel.add(Field_UserName);
				panel.add(label_Port);
				panel.add(Field_Port);
				panel.add(label_ServerAdres);
				panel.add(Field_ServerAdres);
				panel.add(SUBMIT);
				add(panel, BorderLayout.CENTER);
				SUBMIT.addActionListener(this);
				setTitle("LOGIN FORM");
			}

			public void actionPerformed(ActionEvent action) {
				String struserName = Field_UserName.getText();
				Integer port = Integer.parseInt(Field_Port.getText());
				String serverAdres = Field_ServerAdres.getText();
				try {
					
					tradeingclient = new TradingClientImpl();

					FilledOrderListener filledOrderListner = new FilledOrderListener(tradeingclient, (OrderTableModel)orderTableModel);
					tradeingclient.connect(struserName, serverAdres, port, filledOrderListner);
					
					userName = struserName;
					updateLabel_Status(true);
					lofin_frame.setVisible(false);
					lofin_frame.dispose();
				} catch (UnknownHostException e) {
					JOptionPane.showMessageDialog(this, e.getMessage(), Protocol.ERROR_FIELD,JOptionPane.ERROR_MESSAGE);
					disconnected();
				} catch (UserExistException | IOException | MessegeFeedException e) {
					JOptionPane.showMessageDialog(this, e.getMessage(), Protocol.ERROR_FIELD,JOptionPane.ERROR_MESSAGE);
					disconnected();
				}
				
				
			}
	}
		



	}
	
	private void disconnected(){
		if(tradeingclient.isLogin()){
			updateLabel_Status(false);
			tradeingclient.close();
		}
		tradeingclient=null;
	}
	private void updateLabel_Status(boolean enabled) {
		
        Color labelColor = enabled ? Color.green : Color.red;
        
        if (enabled) {
        	connected = true;
        	Label_Status.setText("Connected");
		} else {
			connected = false;
			Label_Status.setText("Disconnected");
		}
        Label_Status.setForeground(labelColor);
    }
}
